import java.awt.Color;
import java.awt.Graphics;
import java.util.Map;

import com.speljohan.rsbot.accessors.NPC;
import com.speljohan.rsbot.bot.Bot;
import com.speljohan.rsbot.event.listeners.PaintListener;
import com.speljohan.rsbot.script.Constants;
import com.speljohan.rsbot.script.Script;
import com.speljohan.rsbot.script.wrappers.RSInterface;
import com.speljohan.rsbot.script.wrappers.RSItem;
import com.speljohan.rsbot.script.wrappers.RSItemTile;
import com.speljohan.rsbot.script.wrappers.RSNPC;
import com.speljohan.rsbot.script.wrappers.RSTile;

public class CrabMelee extends Script implements PaintListener {
	// Script states:
	Color BG = new Color(0, 0, 0, 100);
	public int startHealthXP = 0;
	public int startLevel = 0;
	public int startXP = 0;
	public int fightMode;
	public int DEFENCE = 1;
	public int ATTACK = 0;
	public int STRENGTH = 2;
	public int style = 0;
	public long startTime = System.currentTimeMillis();
	public final int[] foodID = new int[] { 1161, 1965, 1969, 1967, 1895, 1893,
			1891, 1971, 4293, 2142, 4291, 2140, 3228, 9980, 7223, 6297, 6293,
			6295, 6299, 7521, 9988, 7228, 2878, 7568, 2343, 1861, 13433, 315,
			325, 319, 3144, 347, 355, 333, 339, 351, 329, 3381, 361, 10136,
			5003, 379, 365, 373, 7946, 385, 397, 391, 3369, 3371, 3373, 2309,
			2325, 2333, 2327, 2331, 2323, 2335, 7178, 7180, 7188, 7190, 7198,
			7200, 7208, 7210, 7218, 7220, 2003, 2011, 2289, 2291, 2293, 2295,
			2297, 2299, 2301, 2303, 1891, 1893, 1895, 1897, 1899, 1901, 7072,
			7062, 7078, 7064, 7084, 7082, 7066, 7068, 1942, 6701, 6703, 7054,
			6705, 7056, 7060, 2130, 1985, 1993, 1989, 1978, 5763, 5765, 1913,
			5747, 1905, 5739, 1909, 5743, 1907, 1911, 5745, 2955, 5749, 5751,
			5753, 5755, 5757, 5759, 5761, 2084, 2034, 2048, 2036, 2217, 2213,
			2205, 2209, 2054, 2040, 2080, 2277, 2225, 2255, 2221, 2253, 2219,
			2281, 2227, 2223, 2191, 2233, 2092, 2032, 2074, 2030, 2281, 2235,
			2064, 2028, 2187, 2185, 2229 };
	public static final int[] Charms = new int[] { 402, 995, 12158, 12159,
			12160, 12163 };
	final int S_WALKTO_CRABS = 1000;
	final int S_FIGHT_CRABS = 2000;
	final int S_WALKTO_VILLAGE = 3000;
	final int S_WAIT = 4000;
	int state = S_FIGHT_CRABS;

	// Paths:
	RSTile[] toVillage = new RSTile[] { new RSTile(2709, 3722),
			new RSTile(2706, 3714), new RSTile(2706, 3704),
			new RSTile(2705, 3696), new RSTile(2702, 3687) };
	RSTile[] toCrabs = reversePath(toVillage);

	// NPC IDs:
	int[] npcCrabInactive = new int[] { 1266, 1268 };
	int[] npcCrabActive = new int[] { 1265, 1267 };

	// Miscellaneous:
	long waitTime = random(20, 40);
	int foodCheck = random(10, 20);
	int randomRunValue = 45;

	public int antiBan() {
		final int gambleInt = random(1, 9);

		if (gambleInt == 1) {
			return random(2000, 2000);
		}
		if (gambleInt == 2) {
			final int x = random(0, 750);
			final int y = random(0, 500);
			moveMouse(0, 0, x, y);
			log("Anti-ban active");
		}
		return random(500, 1000);
	}

	public int attackCrab() {
		final RSNPC crab = getCrab(npcCrabInactive);

		if (crab != null) {
			if (getMyPlayer().getLocation().equals(crab.getLocation())
					&& !getMyPlayer().isInCombat()) {
				wait(random(500, 1000));
				if (!getMyPlayer().isInCombat()) {
					log("The crabs aren't attacking.");
					takeCharms();
					state = S_WALKTO_VILLAGE;
				}

				return random(750, 1000);
			}

			if (tileOnScreen(crab.getLocation())
					&& distanceTo(crab.getLocation()) <= 10) {
				walkTileMM(crab.getLocation());
				return random(1000, 1500);
			} else if (distanceTo(crab.getLocation()) <= 12) {
				log("Walking to crab.");
				walkTileMM(crab.getLocation());
				return random(750, 1000);
			}
		} else {
			log("Couldn't find a rock crab.");
			wait(random(300, 400));
		}

		return random(500, 1000);
	}

	public void checkHealthEat() {
		int health;

		health = skills.getCurrentSkillLevel(Constants.STAT_HITPOINTS);
		final RSItem food = getInventoryItemByID(foodID);
		if (health <= foodCheck) {
			log("Health is " + health + ", eating.");
			foodCheck = random(15, 25);
			log("Eating: " + food.getID() + ".");
			atInventoryItem(food.getID(), "Eat");
		}
	}

	public boolean detectBlackUnicorn() {
		final RSNPC unicorn = getNearestNPCByName("Black unicorn");

		if (unicorn != null && unicorn.isInteractingWithLocalPlayer()) {
			log("Detected black unicorn.");
			state = S_WALKTO_CRABS;
			return true;
		}
		return false;
	}

	public boolean detectEvilChicken() {
		final RSNPC chicken = getNearestNPCByName("Evil Chicken");

		if (chicken != null && chicken.isInteractingWithLocalPlayer()) {
			log("Detected evil chicken.");
			state = S_WALKTO_VILLAGE;
			return true;
		}
		return false;
	}

	public boolean detectSwarm() {
		final RSNPC swarm = getNearestNPCByName("Swarm");

		if (swarm != null && swarm.isInteractingWithLocalPlayer()) {
			log("Detected swarm.");
			state = S_WALKTO_VILLAGE;
			return true;
		}
		return false;
	}

	//
	// Version information methods:
	//
	@Override
	public String getAuthor() {
		return "Karl";
	}

	public RSNPC getCrab(final int... ids) {
		int Dist = 20;
		RSNPC closest = null;
		final int[] validNPCs = Bot.getClient().getNPCIndexArray();
		final NPC[] npcs = Bot.getClient().getNPCArray();

		for (final int element : validNPCs) {
			if (npcs[element] == null) {
				continue;
			}
			final RSNPC Monster = new RSNPC(npcs[element]);
			try {
				for (final int id : ids) {
					if (id != Monster.getID()) {
						continue;
					}
					final int MonX = Monster.getLocation().getX();
					final int MonY = Monster.getLocation().getY();
					if (MonX <= 2720 && MonX >= 2693 && MonY <= 3731
							&& MonY >= 3714) {
						final int distance = distanceTo(Monster);
						if (distance < Dist) {
							Dist = distance;
							closest = Monster;
							return closest;
						}
					}
					continue;
				}
			} catch (final Exception e) {
			}
		}
		return closest;
	}

	//
	// By ngovil21 - Thanks dude!
	//
	@Override
	public int getEnergy() {
		try {
			return Integer.parseInt(RSInterface.getChildInterface(548, 105)
					.getText());
		} catch (final Exception e) {
		}

		return 0;
	}

	@Override
	public String getName() {
		return "CrabMelee";
	}

	@Override
	public String getScriptCategory() {
		return "Combat";
	}

	@Override
	public String getScriptDescription() {
		String html = "";
		html += "<html>";
		html += "<body>";
		html += "<h2>" + getName() + " v" + getVersion() + "</h2><br>";
		html += "<b>Author:</b> " + getAuthor() + "<br><br>";
		html += "<b>Information: </b><br>";
		html += "Based off Aelin and Veejay's Crab Ranger.<br>";
		html += "<br><b>Instructions: </b><br>";
		html += "Set which style of attack you want to train and start the bot in the EAST crab part.";
		html += "<br>If you dont know where it is check out the forum post for a picture.";
		html += "<br>This bot will eat any food ID's found in the inventory.";
		html += "<center>";
		html += "<br><select name=\"style\"><option selected>Strength<option>Attack<option>Defence</select>";
		// html += "<center>\n";
		// html += "Arguments:<input type=\"text\" name=\"args\">\n";
		// html += "</center>\n";
		html += "</center></body>";
		html += "</html>";
		return html;
	}

	@Override
	public double getVersion() {
		return 1.1;
	}

	@Override
	public int loop() {
		// If energy is over the value specified, then run.
		if (getEnergy() >= randomRunValue && !isRunning()) {
			log("Setting run.");

			setRun(true);
			randomRunValue = random(45, 65);
		}
		if (isLoggedIn()) {
			if (startLevel == 0) {
				startLevel = skills.getCurrentSkillLevel(style);
			}
			if (startXP == 0) {
				startXP = skills.getCurrentSkillExp(style);
			}
		}

		// Prevent running away when under attack.
		if (getMyPlayer().isInCombat() && !detectEvilChicken()
				&& !detectSwarm()) {
			state = S_FIGHT_CRABS;
		}

		// Check if the player needs food.
		checkHealthEat();

		// Is the player currently busy?
		if (getMyPlayer().isMoving() || getMyPlayer().isInCombat()
				|| getMyPlayer().getAnimation() != -1) {
			if (!detectEvilChicken() && !detectSwarm()) {
				return antiBan();
			}
		}
		if (getFightMode() != fightMode) {
			setFightMode(fightMode);
		}

		// Process based on state.
		switch (state) {
		case S_WALKTO_CRABS:
			if (distanceTo(toCrabs[toCrabs.length - 1]) <= 2) {
				log("Arriving at rock crabs, fighting.");
				state = S_FIGHT_CRABS;
				return random(500, 1000);
			} else {
				walkPathMM(randomizePath(toCrabs, 2, 2), 20);
				return random(500, 1000);
			}
		case S_FIGHT_CRABS:
			wait(random(300, 400));
			return attackCrab();
		case S_WALKTO_VILLAGE:
			if (distanceTo(toVillage[toVillage.length - 1]) <= 2) {
				log("Running south.");
				state = S_WAIT;
				return random(100, 500);
			} else {
				walkPathMM(randomizePath(toVillage, 2, 2), 20);
				return random(500, 1000);
			}
		case S_WAIT:
			if (System.currentTimeMillis() - startTime >= waitTime) {
				log("Heading back to crabs.");
				waitTime = random(1200, 1800);
				state = S_WALKTO_CRABS;
				return antiBan();
			} else {
				return antiBan();
			}
		}
		// Return random 500-1000.
		return random(500, 1000);
	}

	@Override
	public void onFinish() {
		Bot.getEventManager().removeListener(PaintListener.class, this);
	}

	public void onRepaint(final Graphics g) {
		if (isLoggedIn()) {
			long millis = System.currentTimeMillis() - startTime;
			final long hours = millis / (1000 * 60 * 60);
			millis -= hours * 1000 * 60 * 60;
			final long minutes = millis / (1000 * 60);
			millis -= minutes * 1000 * 60;
			final long seconds = millis / 1000;
			final int XPChange = skills.getCurrentSkillExp(style) - startXP;
			final int LevelChange = skills.getCurrentSkillLevel(style)
					- startLevel;
			final int Xprint = 20;
			final int Yprint = 256;
			final int nextLvl = skills.getCurrentSkillLevel(style) + 1;
			final int perNextLvl = 100 - skills.getPercentToNextLevel(style);

			g.setColor(BG);
			g.fill3DRect(13, 253, 273, 71, true);
			g.setColor(Color.white);
			g.drawString("Runtime: " + hours + " hours " + minutes
					+ " minutes " + seconds + " seconds.", Xprint, Yprint + 15);
			g.drawString("Current: " + skills.getCurrentSkillLevel(style)
					+ " levels and " + skills.getCurrentSkillExp(style)
					+ " exp.", Xprint, Yprint + 30);
			g.drawString("Gained: " + LevelChange + " levels and " + XPChange
					+ " exp.", Xprint, Yprint + 45);
			g.drawString(skills.getXPToNextLevel(style) + " XP to level "
					+ nextLvl + ", only " + perNextLvl
					+ "% left to next level.", Xprint, Yprint + 60);

		}
	}

	@Override
	public boolean onStart(final Map<String, String> args) {
		if (args.get("style").equals("Strength")) {
			fightMode = 1;
			style = STRENGTH;
		}
		if (args.get("style").equals("Attack")) {
			fightMode = 0;
			style = ATTACK;
		}
		if (args.get("style").equals("Defence")) {
			fightMode = 3;
			style = DEFENCE;
		}
		startLevel = 0;
		startXP = 0;
		return true;
	}

	public void runOn() {
		if (getEnergy() > random(25, 100)) {
			setRun(true);
		}
		openTab(Constants.TAB_INVENTORY);
	}

	public void takeCharms() {
		final RSItemTile charm = getGroundItemByID(CrabMelee.Charms);
		if (charm != null) {
			for (int i = 0; i < CrabMelee.Charms.length - 1; i++) {
				atTile(getGroundItemByID(CrabMelee.Charms), "Take");
			}
		}
	}
}